import { ASSET_TYPES } from '../shared/constant.js'

// 定义生命周期
export const LIFECYCLE_HOOKS = [
  'beforeCreate',
  'created',
  'beforeMount',
  'mounted',
  'beforeUpdate',
  'updated',
  'beforeDestroy',
  'destroyed'
]

// 合并策略
const strats = {}

// 生命周期合并策略: 把全部的生命周期都各自混入成了数组的形式依次调用
function mergeHook(parentVal, childVal) {
  // 如果有儿子
  if (childVal) {
    if (parentVal) {
      // 合并成一个数组
      return parentVal.concat(childVal)
    } else {
      // 包装成一个数组
      return [childVal]
    }
  } else {
    return parentVal
  }
}

LIFECYCLE_HOOKS.forEach((hook) => (strats[hook] = mergeHook))

// 组件 指令 过滤器的合并策略
// 比如有同名的全局组件和自己定义的局部组件 那么parentVal代表全局组件 自己定义的组件是childVal
// 首先会查找自已局部组件有就用自己的  没有就从原型继承全局组件  res.__proto__===parentVal
function mergeAssets(parentVal, childVal) {
  const res = Object.create(parentVal)
  if (childVal) {
    for (const key in childVal) {
      res[key] = childVal[key]
    }
  }
  return res
}
ASSET_TYPES.forEach((type) => (strats[type + 's'] = mergeAssets))

/**
 * 遍历父亲和儿子的属性 进行合并 如果合并的选项有自己的合并策略 那么就是用相应的合并策略
 * - 父子都有并且是对象 => 合并一起
 * - 父亲有 儿子没有 => 使用父亲的
 * - 否则直接用儿子的
 */
export function mergeOptions(parent, child) {
  const options = {}

  // 父亲有
  for (const k in parent) {
    mergeField(k)
  }

  // 父亲没有 儿子有
  // hasOwnProperty => 判断自身是否有某个属性
  const hasOwn = Object.prototype.hasOwnProperty
  for (const k in child) {
    if (!hasOwn.call(parent, k)) {
      mergeField(k)
    }
  }

  function mergeField(k) {
    if (strats[k]) {
      // 如果有自己的合并策略则使用自己的
      options[k] = strats[k](parent[k], child[k])
    } else {
      // 默认合并策略
      options[k] = child[k] ? child[k] : parent[k]
    }
  }

  return options
}

export function isObject(data) {
  //判断是否是对象
  if (typeof data !== 'object' || data == null) {
    return false
  }
  return true
}

export function isReservedTag(tagName) {
  //判断是不是常规html标签
  // 定义常见标签
  let str =
    'html,body,base,head,link,meta,style,title,' +
    'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +
    'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +
    'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +
    's,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +
    'embed,object,param,source,canvas,script,noscript,del,ins,' +
    'caption,col,colgroup,table,thead,tbody,td,th,tr,' +
    'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +
    'output,progress,select,textarea,' +
    'details,dialog,menu,menuitem,summary,' +
    'content,element,shadow,template,blockquote,iframe,tfoot'
  let obj = {}
  str.split(',').forEach((tag) => {
    obj[tag] = true
  })
  return obj[tagName]
}
